/***********************************************************************************
 * 文件名： ly_pid.h
 * 作者： 	刘言
 * 版本： 	1
 * 说明：
 * 		面相对象设计的PID算法计算器，注意不要与单例模式的版本 pid_static 同时使用，会出
 * 现命名冲突。
 * 		PID 计算方法： 控制（输出）值的变化量 = 
 * 				  比例系数 * 偏差值 
 * 				+ 积分系数 * 偏差累加值 
 * 				+ 微分系数 * (偏差值 - 上一个偏差值)
 * 		
 * 修改记录：
 * 	20220715：初版。
***********************************************************************************/
#ifndef _LY_PID_H_
#define _LY_PID_H_

#ifdef __cplusplus
extern "C" {
#endif 

#include "ly_pid_config.h"
#include "polsys.h"

// 确定数据类型

#ifdef _PID_USE_FLOAT
	typedef float input_value_t;
	typedef float ctrl_value_t;
	typedef float inte_value_t;
	typedef float pid_kp_t;
	typedef float pid_ki_t;
	typedef float pid_kd_t;
#else
	#define _PID_CTRL_MAX	((_PID_KP_MAX * _PID_INPUT_MAX + _PID_KI * _PID_MAX_INTE_VALUE + _PID_KD_MAX * (_PID_INPUT_MAX - 0)) / _PID_SCALE)

	#if (_PID_MAX_INTE_VALUE >= (-(_PID_MIN_INTE_VALUE)))
		#define _PID_INTE_MAX _PID_MAX_INTE_VALUE
	#else
		#define _PID_INTE_MAX (-(_PID_MIN_INTE_VALUE))
	#endif

	#if (_PID_INPUT_MAX <= 0X7F)
		typedef s8 input_value_t;
	#elif (_PID_INPUT_MAX <= 0X7FFF)
		typedef s16 input_value_t;
	#elif (_PID_INPUT_MAX <= 0X7FFFFFFF)
		typedef s32 input_value_t;
	#else
		#error "被控量（输入量）这么大就太不应该了。"
	#endif

	#if (_PID_CTRL_MAX <= 0X7F)
		typedef s8 ctrl_value_t;
	#elif (_PID_CTRL_MAX <= 0X7FFF)
		typedef s16 ctrl_value_t;
	#elif (_PID_CTRL_MAX <= 0X7FFFFFFF)
		typedef s32 ctrl_value_t;
	#else
		#error "参数设置的不合理导致控制量过大。"
	#endif

	#if (_PID_INTE_MAX <= 0X7F)
		typedef s8 inte_value_t;
	#elif (_PID_INTE_MAX <= 0X7FFF)
		typedef s16 inte_value_t;
	#elif (_PID_INTE_MAX <= 0X7FFFFFFF)
		typedef s32 inte_value_t;
	#else
		#error "偏差累加值（积分）上下限设置的不合理。"
	#endif

	#if (_PID_KP_MAX <= 0X7F)
		typedef s8 pid_kp_t;
	#elif (_PID_KP_MAX <= 0X7FFF)
		typedef s16 pid_kp_t;
	#elif (_PID_KP_MAX <= 0X7FFFFFFF)
		typedef s32 pid_kp_t;
	#else
		#error "可能的比例系数最大值设置的不合理。"
	#endif

	#if (_PID_KI_MAX <= 0X7F)
		typedef s8 pid_ki_t;
	#elif (_PID_KI_MAX <= 0X7FFF)
		typedef s16 pid_ki_t;
	#elif (_PID_KI_MAX <= 0X7FFFFFFF)
		typedef s32 pid_ki_t;
	#else
		#error "可能的积分系数最大值设置的不合理。"
	#endif

	#if (_PID_KD_MAX <= 0X7F)
		typedef s8 pid_kd_t;
	#elif (_PID_KD_MAX <= 0X7FFF)
		typedef s16 pid_kd_t;
	#elif (_PID_KD_MAX <= 0X7FFFFFFF)
		typedef s32 pid_kd_t;
	#else
		#error "可能的微分系数最大值设置的不合理。"
	#endif

#endif


// ly_pid 类。C中struct模拟class，只包含类的所有属性(private)。
typedef struct _ly_pid
{
#ifdef _PID_USE_DYNAMIC_INTEGRAL	// 启用动态积分
	bool mArrive;		// 已达到标志
#endif
	pid_kp_t mKp;	// 比例系数
	pid_ki_t mKi;	// 积分系数
	pid_kd_t mKd;	// 微分系数
	input_value_t mLastDeviationValue;		// 上一个偏差值
	inte_value_t mIntegralValue;			// 偏差累加值（积分值）
	inte_value_t mIntegralValueMax;			// 积分上限
	inte_value_t mIntegralValueMin;			// 积分下限
}ly_pid;

typedef ly_pid *ly_pid_t;

// 使用类创建对象后使用以下API对对象进行操作。

void PID_init(ly_pid_t this, pid_kp_t kp, pid_ki_t ki, pid_kd_t kd);

// 复位。清零一些状态标志和微积分记忆。
void PID_reset(ly_pid_t this);

STATIC_FORCE_IN_LINE void PID_setKp(ly_pid_t this, pid_kp_t kp){this->mKp = kp;}

STATIC_FORCE_IN_LINE void PID_setKi(ly_pid_t this, pid_ki_t ki){this->mKi = ki;}

STATIC_FORCE_IN_LINE void PID_setKd(ly_pid_t this, pid_kd_t kd){this->mKd = kd;}

STATIC_FORCE_IN_LINE void PID_setIntegralValueMax(ly_pid_t this, inte_value_t new_value)
{
	this->mIntegralValueMax = new_value;
}

STATIC_FORCE_IN_LINE void PID_setIntegralValueMin(ly_pid_t this, inte_value_t new_value)
{
	this->mIntegralValueMin = new_value;
}

// 更新并获取控制（输出）量的变化量。
// 获取的值只是PID算法按照参数计算出的变化量，实际可能超出控制器允许最大或者最小值，需要自行处理。
// target - 目标值
// real - 实际值
// 返回值：控制量的变化量
ctrl_value_t PID_getChange(ly_pid_t this, input_value_t target, input_value_t real);





#ifdef __cplusplus
}
#endif 

#endif
